home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / Random2.0 / Source / Random.m < prev    next >
Text File  |  1995-06-12  |  9KB  |  412 lines

  1. //
  2. // Random
  3. //
  4. // Copyright (C) 1992 Contemporary Design Studios. All rights reserved.
  5. //
  6.  
  7.  
  8. #import "Random.h"
  9. #import <math.h>
  10. #import <stdlib.h>
  11. #import <stdio.h>
  12.  
  13.  
  14. @implementation Random
  15.  
  16.  
  17. //
  18. // version
  19. //
  20.  
  21. + (int)version
  22. {
  23.     return 3;                // Version 3 = Release 2.0.
  24. }
  25.  
  26. //
  27. // initEngineClass:
  28. //
  29.  
  30. - initEngineClass:aClass
  31. {
  32.     return [self initEngineInstance:[[aClass alloc] init]];
  33. }
  34.  
  35.  
  36. //
  37. // initEngineInstance:
  38. //
  39. // DESIGNATED INITIALIZER
  40. //
  41.  
  42. - initEngineInstance:anObject
  43. {
  44.     [super init];
  45.  
  46.     if(![anObject isKindOf:[RandomEngine class]]) {
  47.         //
  48.     // Can't do that!
  49.     //
  50.     }
  51.     
  52.     engine    = anObject;
  53.     engineClass    = [engine class];
  54.     unit    = [engineClass unit];
  55.     
  56.     bytebuffer    = (uchar *)malloc(unit);
  57.     curbit    = 0;
  58.     curbyte    = 0;
  59.     
  60.     [engine makeRandom:bytebuffer];            // Make some bytes.
  61.     
  62.     bitbuffer = bytebuffer[curbyte];
  63.     curbyte++;
  64.     
  65.     return self;
  66. }
  67.  
  68.  
  69. //
  70. // rand
  71. //
  72.  
  73. - (ulong) rand
  74. {
  75.     ulong    temp = 0;
  76.     char    *ptr = (char *)(&temp);
  77.     ulong    i;
  78.     
  79.     for(i = 0; i < 4; i++) {
  80.         if(curbyte == unit) {                // i.e., bytebuffer empty.
  81.         [engine makeRandom:bytebuffer];
  82.         curbyte = 0;
  83.     }
  84.     ptr[i] = bytebuffer[curbyte];
  85.     curbyte++;
  86.     }
  87.     
  88.     return temp;
  89. }
  90.  
  91.  
  92. //
  93. // randMax:
  94. //
  95. // This isn't the most conservative algorithm possible. One could rotate bits and/or
  96. // bytes to try to come up with a value in range. However, the added complexity could
  97. // bog down the code even further. Therefore, until somebody proves that being more
  98. // conservative is useful, or a really clever, yet clear, algorithm presents itself,
  99. // this will suffice. Execution should be reasonably fast, and usage of random bits
  100. // and bytes should be reasonably light with this algorithm.
  101. //
  102.  
  103. - (ulong) randMax:(ulong)max
  104. {
  105.     ulong    ret        = 0;
  106.     ulong    *ptr        = &ret;
  107.     int        i;
  108.     
  109.     if(max == 0) {
  110.         ret = 0;
  111.     }
  112.     else if(max == 1) {                        // One bit needed.
  113.     if(curbit == 8) {
  114.         if(curbyte == unit) {
  115.         [engine makeRandom:bytebuffer];
  116.         curbyte = 0;
  117.         }
  118.         bitbuffer = bytebuffer[curbyte];
  119.         curbyte++;
  120.         curbit = 0;
  121.     }
  122.     
  123.     ret = (bitbuffer & (0x01 << curbit) != 0);
  124.     curbit++;
  125.     }
  126.     else if(max <= 0x000000ff) {                // One byte needed.
  127.         do {
  128.         if(curbyte == unit) {
  129.         [engine makeRandom:bytebuffer];
  130.         curbyte = 0;
  131.         }
  132.         ret = bytebuffer[curbyte];
  133.         curbyte++;
  134.     } while (ret > max);
  135.     }
  136.     else if(max <= 0x0000ffff) {                // Two bytes needed.
  137.         do {
  138.         for(i = 0; i < 2; i++) {
  139.         if(curbyte == unit) {
  140.             [engine makeRandom:bytebuffer];
  141.             curbyte = 0;
  142.         }
  143.         ptr[i + 2] = bytebuffer[curbyte];
  144.         curbyte++;
  145.         }
  146.     } while (ret > max);
  147.     }
  148.     else if(max <= 0x00ffffff) {                // Three bytes needed.
  149.         do {
  150.         for(i = 0; i < 3; i++) {
  151.         if(curbyte == unit) {
  152.             [engine makeRandom:bytebuffer];
  153.             curbyte = 0;
  154.         }
  155.         ptr[i + 1] = bytebuffer[curbyte];
  156.         curbyte++;
  157.         }
  158.     } while (ret > max);
  159.     } 
  160.     else {                            // Four bytes needed.
  161.         do {
  162.         for(i = 0; i < 4; i++) {
  163.         if(curbyte == unit) {
  164.             [engine makeRandom:bytebuffer];
  165.             curbyte = 0;
  166.         }
  167.         ptr[i] = bytebuffer[curbyte];
  168.         curbyte++;
  169.         }
  170.     } while (ret > max);
  171.     }
  172.     
  173.     return ret;
  174. }
  175.  
  176.  
  177. //
  178. // randMin:max:
  179. //
  180.  
  181. - (ulong)randMin:(ulong)min max:(ulong)max
  182. {
  183.     return min + [self randMax:(max - min)];
  184. }
  185.  
  186.  
  187. //
  188. // percent
  189. //
  190. // The information in the following exerpt was used to determine the
  191. // construction of a double-precision number with a value between 0.0 and
  192. // 1.0. It turns out to be easiest to construct one with a mantissa of:
  193. //
  194. // 1.rrrrrrrrrr rrrrrrrrrr rrrrrrrrrr rrrrrrrrrr rrrrrrrrrr rr
  195. // 
  196. // Where "r" stands for a random bit, and where the exponent is 0, i.e.
  197. // E is 1023, or 01111111111. Of course, the sign bit is 0. So, the
  198. // resulting number is:
  199. //
  200. // 00111111 1111rrrr rrrrrrrr rrrrrrrr rrrrrrrr rrrrrrrr rrrrrrrr rrrrrrrr
  201. //
  202. // Nicely enough, there is only 1 byte which is a mix of constant and
  203. // random bits. So, the trick is to generate 7 bytes of random data, and
  204. // then to overlay the constant 1111 into the high-order nibble of the
  205. // 2nd byte. Then, the first byte is just the constant 00111111.
  206. //
  207. // Of course, this is technically platform dependant, which is a no-no,
  208. // but I suppose if we move it to another machine, there may be a function
  209. // to convert from XDR format (which this is) to the local format (one can
  210. // hope), which would save us.
  211. //
  212. // -------------------------------- EXERPT --------------------------------
  213. // 
  214. // Network Working Group                             Sun Microsystems, Inc.
  215. // Request for Comments: 1014                                     June 1987
  216. // 
  217. // 
  218. //                XDR: External Data Representation Standard
  219. // 
  220. // ------------------------------------------------------------------------
  221. // 
  222. // 3.7 Double-precision Floating-point
  223. // 
  224. //    The standard defines the encoding for the double-precision floating-
  225. //    point data type "double" (64 bits or 8 bytes).  The encoding used is
  226. //    the IEEE standard for normalized double-precision floating-point
  227. //    numbers [3].  The standard encodes the following three fields, which
  228. //    describe the double-precision floating-point number:
  229. // 
  230. //       S: The sign of the number.  Values 0 and 1 represent positive and
  231. //          negative, respectively.  One bit.
  232. // 
  233. //       E: The exponent of the number, base 2.  11 bits are devoted to
  234. //          this field.  The exponent is biased by 1023.
  235. // 
  236. //       F: The fractional part of the number's mantissa, base 2.  52 bits
  237. //          are devoted to this field.
  238. // 
  239. //    Therefore, the floating-point number is described by:
  240. // 
  241. //          (-1)**S * 2**(E-Bias) * 1.F
  242. // 
  243. //    It is declared as follows:
  244. // 
  245. //          double identifier;
  246. // 
  247. //          +------+------+------+------+------+------+------+------+
  248. //          |byte 0|byte 1|byte 2|byte 3|byte 4|byte 5|byte 6|byte 7|
  249. //          S|    E   |                    F                        |
  250. //          +------+------+------+------+------+------+------+------+
  251. //          1|<--11-->|<-----------------52 bits------------------->|
  252. //          <-----------------------64 bits------------------------->
  253. //                                         DOUBLE-PRECISION FLOATING-POINT
  254. // 
  255. //    Just as the most and least significant bytes of a number are 0 and 3,
  256. //    the most and least significant bits of a double-precision floating-
  257. //    point number are 0 and 63.  The beginning bit (and most significant
  258. //    bit) offsets of S, E , and F are 0, 1, and 12, respectively.  Note
  259. //    that these numbers refer to the mathematical positions of the bits,
  260. //    and NOT to their actual physical locations (which vary from medium to
  261. //    medium).
  262. // 
  263. //    The IEEE specifications should be consulted concerning the encoding
  264. //    for signed zero, signed infinity (overflow), and denormalized numbers
  265. //    (underflow) [3].  According to IEEE specifications, the "NaN" (not a
  266. //    number) is system dependent and should not be used externally.
  267. // 
  268. // ------------------------------------------------------------------------
  269. // 
  270. //    [3]  "IEEE Standard for Binary Floating-Point Arithmetic", ANSI/IEEE
  271. //         Standard 754-1985, Institute of Electrical and Electronics
  272. //         Engineers, August 1985.
  273. // 
  274. // ------------------------------------------------------------------------
  275. // 
  276.  
  277. - (double)percent
  278. {
  279.     double    temp;
  280.     int        i;
  281.     
  282.     for(i = 1; i < 8; i++) {
  283.         if(curbyte == unit) {                // i.e., bytebuffer empty.
  284.         [engine makeRandom:bytebuffer];
  285.         curbyte = 0;
  286.     }
  287.     ((uchar *)(&temp))[i] = bytebuffer[curbyte];
  288.     curbyte++;
  289.     }
  290.     
  291.     ((ulong *)(&temp))[0] &= ((ulong)0x000fffff);
  292.     ((ulong *)(&temp))[0] |= ((ulong)0x3ff00000);
  293.     
  294.     return (temp - 1.0);
  295. }
  296.  
  297.  
  298. //
  299. // bool
  300. //
  301.  
  302. - (BOOL)bool
  303. {
  304.     BOOL    ret;
  305.     
  306.     if(curbit == 8) {
  307.     if(curbyte == unit) {
  308.         [engine makeRandom:bytebuffer];
  309.         curbyte = 0;
  310.     }
  311.     bitbuffer = bytebuffer[curbyte];
  312.     curbyte++;
  313.     curbit = 0;
  314.     }
  315.     
  316.     ret = (bitbuffer & (0x01 << curbit) != 0);
  317.     curbit++;
  318.         
  319.     return ret;
  320. }
  321.  
  322.  
  323. //
  324. // randFunc:
  325. //
  326.  
  327. - (double)randFunc:(ddfunc)func
  328. {
  329.     return (*func)([self percent]);
  330. }
  331.  
  332.  
  333. //
  334. // read:
  335. //
  336.  
  337. - read:(NXTypedStream *)stream
  338. {
  339.     int        i;
  340.     
  341.     [super read:stream];
  342.     
  343.     //
  344.     // Read in the engine:
  345.     //
  346.     
  347.     NXReadTypes(stream, "@", &engine);
  348.     
  349.     //
  350.     // Set related instance variables:
  351.     //
  352.     
  353.     engineClass    = [engine class];
  354.     unit    = [engineClass unit];
  355.     bytebuffer    = (uchar *)malloc(unit);
  356.     curbit    = 0;
  357.     curbyte    = 0;
  358.     
  359.     //
  360.     // Read in the buffers and buffer pointers:
  361.     //
  362.     
  363.     NXReadTypes(stream, "c", &bitbuffer);
  364.     
  365.     for(i = 0; i < unit; i++) {
  366.         NXReadTypes(stream, "c", &(bytebuffer[i]));
  367.     }
  368.     
  369.     NXReadTypes(stream, "ii", &curbit, &curbyte);
  370.     
  371.     return self;
  372. }
  373.  
  374.  
  375. //
  376. // write:
  377. //
  378.  
  379. - write:(NXTypedStream *)stream
  380. {
  381.     int        i;
  382.     
  383.     [super write:stream];
  384.     
  385.     //
  386.     // Write out the engine:
  387.     //
  388.     
  389.     NXWriteTypes(stream, "@", &engine);
  390.     
  391.     //
  392.     // Write out the buffers and buffer pointers:
  393.     //
  394.     
  395.     NXWriteTypes(stream, "c", &bitbuffer);
  396.     
  397.     for(i = 0; i < unit; i++) {
  398.         NXWriteTypes(stream, "c", &(bytebuffer[i]));
  399.     }
  400.     
  401.     NXWriteTypes(stream, "ii", &curbit, &curbyte);
  402.     
  403.     return self;
  404. }
  405.  
  406.  
  407. @end
  408.  
  409.  
  410. //
  411. // End of file.
  412. //